home *** CD-ROM | disk | FTP | other *** search
- This file is cd.def, from which is created cd.c. It implements the
- builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
-
- Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
-
- This file is part of GNU Bash, the Bourne Again SHell.
-
- Bash is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 1, or (at your option) any later
- version.
-
- Bash is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License along
- with Bash; see the file COPYING. If not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- $PRODUCES cd.c
-
- #include <stdio.h>
- #include <sys/param.h>
- #include "../shell.h"
- #include "../maxpath.h"
-
- static int change_to_directory (), cd_to_string ();
-
- /* Keeps track of the current working directory. */
- extern char *the_current_working_directory;
-
- /* By default, follow the symbolic links as if they were real directories
- while hacking the `cd' command. This means that `cd ..' moves up in
- the string of symbolic links that make up the current directory, instead
- of the absolute directory. The shell variable `nolinks' controls this
- flag. */
- int follow_symbolic_links = 1;
-
- $BUILTIN cd
- $FUNCTION cd_builtin
- $SHORT_DOC cd [dir]
- Change the current directory to DIR. The variable $HOME is the
- default DIR. The variable $CDPATH defines the search path for
- the directory containing DIR. Alternative directory names are
- separated by a colon (:). A null directory name is the same as
- the current directory, i.e. `.'. If DIR begins with a slash (/),
- then $CDPATH is not used. If the directory is not found, and the
- shell variable `cdable_vars' exists, then try the word as a variable
- name. If that variable has a value, then cd to the value of that
- variable.
- $END
-
- int
- cd_builtin (list)
- WORD_LIST *list;
- {
- char *dirname;
-
- {
- extern int restricted;
- if (restricted)
- {
- builtin_error ("Privileged command");
- return (EXECUTION_FAILURE);
- }
- }
-
- if (list)
- {
- char *extract_colon_unit ();
- char *path_string = get_string_value ("CDPATH");
- char *path;
- int index = 0;
-
- dirname = list->word->word;
-
- if (path_string && !absolute_pathname (dirname))
- {
- while ((path = extract_colon_unit (path_string, &index)))
- {
- char *dir;
-
- if (*path && (*path == '~'))
- {
- char *tilde_expand (), *te_string = tilde_expand (path);
-
- free (path);
- path = te_string;
- }
-
- if (!*path)
- {
- free (path);
- path = savestring ("."); /* by definition. */
- }
-
- dir = (char *)alloca (2 + strlen (dirname) + strlen (path));
-
- if (!dir)
- fatal_error ("Out of memory");
-
- strcpy (dir, path);
- if (path[strlen (path) - 1] != '/')
- strcat (dir, "/");
- strcat (dir, dirname);
- free (path);
-
- if (change_to_directory (dir))
- {
- if (strncmp (dir, "./", 2) != 0)
- printf ("%s\n", dir);
- dirname = dir;
-
- goto bind_and_exit;
- }
- }
- }
-
- if (!change_to_directory (dirname))
- {
- /* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
- if (dirname[0] == '-' && dirname[1] == '\0')
- {
- char *t = get_string_value ("OLDPWD");
-
- if (t && change_to_directory (t))
- goto bind_and_exit;
- }
-
- /* If the user requests it, then perhaps this is the name of
- a shell variable, whose value contains the directory to
- change to. If that is the case, then change to that
- directory. */
- if (find_variable ("cdable_vars"))
- {
- char *t = get_string_value (dirname);
-
- if (t && change_to_directory (t))
- {
- printf ("%s\n", t);
- goto bind_and_exit;
- }
- }
-
- file_error (dirname);
- return (EXECUTION_FAILURE);
- }
- goto bind_and_exit;
- }
- else
- {
- dirname = get_string_value ("HOME");
-
- if (!dirname)
- return (EXECUTION_FAILURE);
-
- if (!change_to_directory (dirname))
- {
- file_error (dirname);
- return (EXECUTION_FAILURE);
- }
-
- bind_and_exit:
- {
- char *get_working_directory (), *get_string_value ();
- char *directory = get_working_directory ("cd");
-
- bind_variable ("OLDPWD", get_string_value ("PWD"));
- bind_variable ("PWD", directory);
-
- if (directory)
- free (directory);
- }
- return (EXECUTION_SUCCESS);
- }
- }
-
- $BUILTIN pwd
- $FUNCTION pwd_builtin
- $SHORT_DOC pwd
- Print the current working directory.
- $END
-
- /* Non-zero means that pwd always give verbatim directory, regardless of
- symbolic link following. */
- static int verbatim_pwd = 1;
-
- /* Print the name of the current working directory. */
- pwd_builtin (list)
- WORD_LIST *list;
- {
- char *get_working_directory (), *getwd (), *directory;
-
- no_args (list);
-
- if (verbatim_pwd)
- {
- char *buffer = (char *)xmalloc (MAXPATHLEN);
- directory = getwd (buffer);
-
- if (!directory)
- {
- builtin_error ("%s", buffer);
- free (buffer);
- }
- }
- else
- {
- directory = get_working_directory ("pwd");
- }
-
- if (directory)
- {
- printf ("%s\n", directory);
- fflush (stdout);
- free (directory);
- return (EXECUTION_SUCCESS);
- }
- else
- return (EXECUTION_FAILURE);
- }
-
- $BUILTIN pushd
- $FUNCTION pushd_builtin
- $DEPENDS_ON PUSHD_AND_POPD
- $SHORT_DOC pushd [dir | +n | -n]
- Adds a directory to the top of the directory stack, or rotates
- the stack, making the new top of the stack the current working
- directory. With no arguments, exchanges the top two directories.
-
- +n Rotates the stack so that the Nth directory (counting
- from the left of the list shown by `dirs') is at the top.
-
- -n Rotates the stack so that the Nth directory (counting
- from the right) is at the top.
-
- dir adds DIR to the directory stack at the top, making it the
- new current working directory.
-
- You can see the directory stack with the `dirs' command.
- If the variable `pushd_silent' is not set and the pushd command
- was successful, a `dirs' is be performed as well.
- $END
-
- #if defined (PUSHD_AND_POPD)
- /* Some useful commands whose behaviour has been observed in Csh. */
-
- /* The list of remembered directories. */
- static char **pushd_directory_list = (char **)NULL;
-
- /* Number of existing slots in this list. */
- static int directory_list_size = 0;
-
- /* Offset to the end of the list. */
- static int directory_list_offset = 0;
-
- pushd_builtin (list)
- WORD_LIST *list;
- {
- char *temp, *current_directory, *get_working_directory ();
- int j = directory_list_offset - 1;
- char direction = '+';
-
- /* If there is no argument list then switch current and
- top of list. */
- if (!list)
- {
- if (!directory_list_offset)
- {
- builtin_error ("No other directory");
- return (EXECUTION_FAILURE);
- }
-
- current_directory = get_working_directory ("pushd");
- if (!current_directory)
- return (EXECUTION_FAILURE);
-
- temp = pushd_directory_list[j];
- pushd_directory_list[j] = current_directory;
- goto change_to_temp;
- }
- else
- {
- direction = *(list->word->word);
- if (direction == '+' || direction == '-')
- {
- int num;
- if (1 == sscanf (&(list->word->word)[1], "%d", &num))
- {
- if (direction == '-')
- num = directory_list_offset - num;
-
- if (num > directory_list_offset || num < 0)
- {
- if (!directory_list_offset)
- builtin_error ("Directory stack empty");
- else
- builtin_error ("Stack contains only %d directories",
- directory_list_offset + 1);
- return (EXECUTION_FAILURE);
- }
- else
- {
- /* Rotate the stack num times. Remember, the
- current directory acts like it is part of the
- stack. */
- temp = get_working_directory ("pushd");
-
- if (!num)
- goto change_to_temp;
-
- do
- {
- char *top =
- pushd_directory_list[directory_list_offset - 1];
-
- for (j = directory_list_offset - 2; j > -1; j--)
- pushd_directory_list[j + 1] = pushd_directory_list[j];
-
- pushd_directory_list[j + 1] = temp;
-
- temp = top;
- num--;
- }
- while (num);
-
- temp = savestring (temp);
- change_to_temp:
- {
- int tt = EXECUTION_FAILURE;
-
- if (temp)
- {
- tt = cd_to_string (temp);
- free (temp);
- }
-
- if ((tt == EXECUTION_SUCCESS) &&
- (!find_variable ("pushd_silent")))
- dirs_builtin ((WORD_LIST *)NULL);
-
- return (tt);
- }
- }
- }
- }
-
- /* Change to the directory in list->word->word. Save the current
- directory on the top of the stack. */
- current_directory = get_working_directory ("pushd");
- if (!current_directory)
- return (EXECUTION_FAILURE);
-
- if (cd_builtin (list) == EXECUTION_SUCCESS)
- {
- if (directory_list_offset == directory_list_size)
- {
- pushd_directory_list = (char **)
- xrealloc (pushd_directory_list,
- (directory_list_size += 10) * sizeof (char *));
- }
- pushd_directory_list[directory_list_offset++] = current_directory;
-
- if (!find_variable ("pushd_silent"))
- dirs_builtin ((WORD_LIST *)NULL);
-
- return (EXECUTION_SUCCESS);
- }
- else
- {
- free (current_directory);
- return (EXECUTION_FAILURE);
- }
- }
- }
- #endif /* PUSHD_AND_POPD */
-
- $BUILTIN dirs
- $FUNCTION dirs_builtin
- $DEPENDS_ON PUSHD_AND_POPD
- $SHORT_DOC dirs [-l]
- Display the list of currently remembered directories. Directories
- find their way onto the list with the `pushd' command; you can get
- back up through the list with the `popd' command.
-
- The -l flag specifies that `dirs' should not print shorthand versions
- of directories which are relative to your home directory. This means
- that `~/bin' might be displayed as `/homes/bfox/bin'.
- $END
-
- #if defined (PUSHD_AND_POPD)
- /* Print the current list of directories on the directory stack. */
- dirs_builtin (list)
- WORD_LIST *list;
- {
- register int i, format = 0;
- char *temp, *polite_directory_format (), *get_working_directory ();
-
- /* Maybe do long form? */
- if (list)
- {
- if (strcmp (list->word->word, "-l") == 0)
- format++;
- else if (!format || list->next)
- {
- bad_option (list->word->word);
- return (EXECUTION_FAILURE);
- }
- }
-
- /* The first directory printed is always the current working directory. */
- temp = get_working_directory ("dirs");
- if (!temp)
- temp = savestring ("<no directory>");
- printf ("%s", format ? temp : polite_directory_format (temp));
- free (temp);
-
- /* Now print any directories in the array. */
- for (i = (directory_list_offset - 1); i > -1; i--)
- printf (" %s", format ? pushd_directory_list[i] :
- polite_directory_format (pushd_directory_list[i]));
-
- putchar ('\n');
- fflush (stdout);
- return (EXECUTION_SUCCESS);
- }
- #endif /* PUSHD_AND_POPD */
-
- $BUILTIN popd
- $FUNCTION popd_builtin
- $DEPENDS_ON PUSHD_AND_POPD
- $SHORT_DOC popd [+n | -n]
- Removes entries from the directory stack. With no arguments,
- removes the top directory from the stack, and cd's to the new
- top directory.
-
- +n removes the Nth entry counting from the left of the list
- shown by `dirs', starting with zero. For example: `popd +0'
- removes the first directory, `popd +1' the second.
-
- -n removes the Nth entry counting from the right of the list
- shown by `dirs', starting with zero. For example: `popd -0'
- removes the last directory, `popd -1' the next to last.
-
- You can see the directory stack with the `dirs' command.
- If the variable 'pushd_silent' is not set and the popd command
- was successful, a 'dirs' will be performed as well..
- $END
-
- #if defined (PUSHD_AND_POPD)
- /* Pop the directory stack, and then change to the new top of the stack.
- If LIST is non-null it should consist of a word +N or -N, which says
- what element to delete from the stack. The default is the top one. */
- popd_builtin (list)
- WORD_LIST *list;
- {
- register int i;
- int which = 0;
- char direction = '+';
-
- if (list)
- {
- direction = *(list->word->word);
-
- if ((direction != '+' && direction != '-') ||
- (1 != sscanf (&((list->word->word)[1]), "%d", &which)))
- {
- builtin_error ("bad arg `%s'", list->word->word);
- return (EXECUTION_FAILURE);
- }
- }
-
- if (which > directory_list_offset || (!directory_list_offset && !which))
- {
- if (!directory_list_offset)
- builtin_error ("Directory stack empty");
- else
- builtin_error ("Stack contains only %d directories",
- directory_list_offset + 1);
- return (EXECUTION_FAILURE);
- }
-
- /* Handle case of no specification, or top of stack specification. */
- if ((direction == '+' && which == 0) ||
- (direction == '-' && which == directory_list_offset))
- {
- i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
- if (i != EXECUTION_SUCCESS)
- return (i);
- free (pushd_directory_list[--directory_list_offset]);
- }
- else
- {
- /* Since an offset other than the top directory was specified,
- remove that directory from the list and shift the remainder
- of the list into place. */
-
- if (direction == '+')
- i = directory_list_offset - which;
- else
- i = which;
-
- free (pushd_directory_list[i]);
- directory_list_offset--;
-
- /* Shift the remainder of the list into place. */
- for (; i < directory_list_offset; i++)
- pushd_directory_list[i] = pushd_directory_list[i + 1];
- }
-
- if (!find_variable ("pushd_silent"))
- dirs_builtin ((WORD_LIST *)NULL);
-
- return (EXECUTION_SUCCESS);
- }
- #endif /* PUSHD_AND_POPD */
-
- /* Do the work of changing to the directory NEWDIR. Handle symbolic
- link following, etc. */
- static int
- change_to_directory (newdir)
- char *newdir;
- {
- char *get_working_directory (), *make_absolute ();
- char *t;
-
- if (follow_symbolic_links)
- {
- if (!the_current_working_directory)
- {
- t = get_working_directory ("cd_links");
- if (t)
- free (t);
- }
-
- if (the_current_working_directory)
- t = make_absolute (newdir, the_current_working_directory);
- else
- t = savestring (newdir);
-
- /* Get rid of trailing `/'. */
- {
- register int len_t = strlen (t);
- if (len_t > 1)
- {
- --len_t;
- if (t[len_t] == '/')
- t[len_t] = '\0';
- }
- }
-
- if (chdir (t) < 0)
- {
- free (t);
- return (0);
- }
-
- if (the_current_working_directory)
- strcpy (the_current_working_directory, t);
-
- free (t);
- return (1);
- }
- else
- {
- if (chdir (newdir) < 0)
- return (0);
- else
- return (1);
- }
- }
-
- /* Switch to the directory in NAME. This uses the cd_builtin to do the work,
- so if the result is EXECUTION_FAILURE then an error message has already
- been printed. */
- static int
- cd_to_string (name)
- char *name;
- {
- extern WORD_LIST *make_word_list ();
- WORD_LIST *tlist = make_word_list (make_word (name), NULL);
- int result = (cd_builtin (tlist));
- dispose_words (tlist);
- return (result);
- }
-
-